package com.wolfcode.audit.service.impl;


import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import com.wolfcode.appointment.domain.BusServiceItem;
import com.wolfcode.appointment.enums.AuditEnum;
import com.wolfcode.appointment.enums.BusCarPackageAuditEnum;
import com.wolfcode.appointment.enums.CarPackageEnum;
import com.wolfcode.appointment.mapper.BusServiceitemMapper;
import com.wolfcode.audit.domain.enums.BusPackageAuditEnum;
import com.wolfcode.audit.domain.info.HistoricCommentInfo;
import com.wolfcode.audit.domain.vo.BusCarPackageAuditVo;
import com.wolfcode.common.core.domain.model.LoginUser;
import com.wolfcode.common.utils.DateUtils;
import com.wolfcode.common.utils.PageUtils;
import com.wolfcode.common.utils.SecurityUtils;
import com.wolfcode.flow.domain.BusBpmnInfo;
import com.wolfcode.flow.mapper.BusBpmnInfoMapper;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.wolfcode.audit.mapper.BusCarPackageAuditMapper;
import com.wolfcode.audit.domain.BusCarPackageAudit;
import com.wolfcode.audit.service.IBusCarPackageAuditService;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;


/**
 * 套餐审核Service业务层处理
 * 
 * @author wolfcode
 * @date 2022-11-28
 */
@Service
public class BusCarPackageAuditServiceImpl implements IBusCarPackageAuditService 
{
    @Autowired
    private BusCarPackageAuditMapper busCarPackageAuditMapper;
    @Autowired
    private BusBpmnInfoMapper busBpmnInfoMapper;
    @Autowired
    private BusServiceitemMapper busServiceitemMapper;
    @Autowired
    private TaskService taskService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private RepositoryService repositoryService;
    /**
     * 查询套餐审核
     * 
     * @param id 套餐审核主键
     * @return 套餐审核
     */
    @Override
    public BusCarPackageAudit selectBusCarPackageAuditById(Long id)
    {
        return busCarPackageAuditMapper.selectBusCarPackageAuditById(id);
    }

    /**
     * 查询套餐审核列表
     * 
     * @param busCarPackageAudit 套餐审核
     * @return 套餐审核
     */
    @Override
    public List<BusCarPackageAudit> selectBusCarPackageAuditList(BusCarPackageAudit busCarPackageAudit)
    {
        return busCarPackageAuditMapper.selectBusCarPackageAuditList(busCarPackageAudit);
    }

    /**
     * 新增套餐审核
     * 
     * @param busCarPackageAudit 套餐审核
     * @return 结果
     */
    @Override
    public int insertBusCarPackageAudit(BusCarPackageAudit busCarPackageAudit)
    {
        busCarPackageAudit.setCreateTime(DateUtils.getNowDate());
        return busCarPackageAuditMapper.insertBusCarPackageAudit(busCarPackageAudit);
    }

    /**
     * 修改套餐审核
     * 
     * @param busCarPackageAudit 套餐审核
     * @return 结果
     */
    @Override
    public int updateBusCarPackageAudit(BusCarPackageAudit busCarPackageAudit)
    {
        return busCarPackageAuditMapper.updateBusCarPackageAudit(busCarPackageAudit);
    }

    /**
     * 批量删除套餐审核
     * 
     * @param ids 需要删除的套餐审核主键
     * @return 结果
     */
    @Override
    public int deleteBusCarPackageAuditByIds(Long[] ids)
    {
        return busCarPackageAuditMapper.deleteBusCarPackageAuditByIds(ids);
    }

    /**
     * 删除套餐审核信息
     * 
     * @param id 套餐审核主键
     * @return 结果
     */
    @Override
    public int deleteBusCarPackageAuditById(Long id)
    {
        return busCarPackageAuditMapper.deleteBusCarPackageAuditById(id);
    }

    /**
     * 我的代办
     * @return
     */
    @Override
    public List<BusCarPackageAudit> todoQuery(BusCarPackageAuditVo busCarPackageAuditVo) {
        // 校验
        // 1 获取套餐审核流程定义信息
        BusBpmnInfo bpmnInfo = busBpmnInfoMapper.getByBpmnType(
                BusCarPackageAuditEnum.FLOW_AUDIT_TYPE.ordinal());
        Assert.notNull(bpmnInfo,"请先上传流程定义");
        // 当前登录的用户id
        // 查询任务列表
        String userId = SecurityUtils.getUserId().toString();
        List<Task> taskList = taskService.createTaskQuery()
                .processDefinitionKey(bpmnInfo.getProcessDefinitionKey())
                .taskAssignee(userId)
                .list();
        if (CollectionUtils.isEmpty(taskList)) {
            return Collections.emptyList();
        }
        // ru_task --- procIds
        Set<String> processInstanceIds = taskList.stream()
                .map(task -> task.getProcessInstanceId())
                .collect(Collectors.toSet());
        // ru_execution --- business_keys
        List<ProcessInstance> processInstances = runtimeService.createProcessInstanceQuery()
                .processInstanceIds(processInstanceIds).list();
        List<String> businessKeys = processInstances.stream().map(processInstance ->
                processInstance.getBusinessKey()).collect(Collectors.toList());
        PageUtils.startPage();
        // bus_car_package_audit -- 套餐信息
        //  sql语法错误，businessKeys 为空
        List<BusCarPackageAudit> busCarPackageAudits = busCarPackageAuditMapper
                .selectBusCarPackageAuditListByBusinessKeys(businessKeys);

        return busCarPackageAudits;
    }

    /**
     * 审核人审核
     * @param auditVo
     */
    @Override
    public void audit(BusCarPackageAuditVo auditVo) {
        // 校验
        Assert.notNull(auditVo,"非法参数");
        // 1 获取套餐信息
        BusCarPackageAudit busCarPackageAudit = busCarPackageAuditMapper
                .selectBusCarPackageAuditById(auditVo.getId());
        Assert.notNull(busCarPackageAudit,"该套餐信息不存在");
        // 2 校验审核状态，审核中才允许审核
        Assert.state(BusPackageAuditEnum.AUDITING.ordinal() == busCarPackageAudit.getStatus(),
                "审核中的才允许审核");
        LoginUser loginUser = SecurityUtils.getLoginUser();
        // 获取流程实例目前的任务(根据流程实例id获取任务)
        Task task = taskService.createTaskQuery()
                .processInstanceId(busCarPackageAudit.getInstanceId()).singleResult();
        Assert.notNull(task,"任务不存在");
        // 3 添加批注，完成，让流程往下走
        String auditLabel = auditVo.isAuditStatus() ? "同意" : "拒绝";
        String comment = loginUser.getUsername() + "["+ auditLabel  +"]," + auditVo.getInfo();
        // taskId 任务id
        // processInstanceId 流程实例id
        // message 批注信息
        taskService.addComment(task.getId(), busCarPackageAudit.getInstanceId(),comment);
        // taskId
        // variableName
        // value
        // 设置流程变量（shopOwner,ru_task_def_key）
        //shopOwner=false --- 拒绝根据bpmn图，直接结束时间
        taskService.setVariable(task.getId(),task.getTaskDefinitionKey(),auditVo.isAuditStatus());
        // 完成任务
        taskService.complete(task.getId());
        // 4 根据审核状态（同意还是拒绝）更新套餐审核和服务单项的状态
        BusCarPackageAudit audit = new BusCarPackageAudit();
        BusServiceItem serviceItem = new BusServiceItem();
        if (auditVo.isAuditStatus()) {
            // 同意
            // 看一下有没有下个任务，没有代表任务结束
            Task nextTask = taskService.createTaskQuery()
                    .processInstanceId(busCarPackageAudit.getInstanceId()).singleResult();

            // 有下个任务，不处理
            // 没有下个任务，代表流程结束，更新一些审核状态，审核通过
            if (nextTask == null) {
                updateState(busCarPackageAudit, audit, serviceItem, BusPackageAuditEnum.PASS, AuditEnum.PASS);
            }
        } else {
            // 拒绝
            updateState(busCarPackageAudit, audit, serviceItem, BusPackageAuditEnum.REJECT, AuditEnum.REJECT);
        }
    }

    /**
     * 审批历史
     * @param instanceId
     * @return
     */
    @Override
    public List<HistoricCommentInfo> listHistory(String instanceId) {
        Assert.notNull(instanceId,"非法参数");
        List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(instanceId)
                .orderByHistoricTaskInstanceEndTime()
                .asc()
                .list();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
        // 处理历史任务列表
        List<HistoricCommentInfo> historicCommentInfos = historicTaskInstances.stream().map(taskInstance -> {
            HistoricCommentInfo historicCommentInfo = new HistoricCommentInfo();
            // 任务名称
            historicCommentInfo.setTaskName(taskInstance.getName());
            // 开始时间
            historicCommentInfo.setStartTime(sdf.format(taskInstance.getStartTime()));
            // 结束时间
            if (taskInstance.getEndTime() != null) {
                historicCommentInfo.setEndTime(sdf.format(taskInstance.getEndTime()));
            }
            // 持续时间
            if (taskInstance.getDurationInMillis() != null) {
                // TODO toString 看时间是否正确，改了代码
                historicCommentInfo.setDurationInMillis(taskInstance.getDurationInMillis().toString());
            }
            // 评论
            // 评论设计有问题，应该设计在历史表中，不是运行时的，
            List<Comment> comments = taskService.getTaskComments(taskInstance.getId(), "comment");
            if (!CollectionUtils.isEmpty(comments)) {
                historicCommentInfo.setComment(comments.get(0).getFullMessage());
            }
            return historicCommentInfo;

        }).collect(Collectors.toList());
        return historicCommentInfos;
    }

    public void updateState(BusCarPackageAudit busCarPackageAudit, BusCarPackageAudit audit, BusServiceItem serviceItem, BusPackageAuditEnum reject, AuditEnum reject2) {
        // 假如拒绝，更新一些审核状态，审核拒绝
        audit.setId(busCarPackageAudit.getId());
        // 审核套餐审核通过
        audit.setStatus(reject.ordinal());
        busCarPackageAuditMapper.updateBusCarPackageAudit(audit);
        // 服务单项审核通过
        serviceItem.setId(busCarPackageAudit.getServiceItemId());
        serviceItem.setAuditStatus(reject2.ordinal());
        busServiceitemMapper.updateBusServiceitem(serviceItem);
    }


    /**
     * 查看审核进度
     * @param id  审核套餐id
     * @return
     */
    @Override
    public InputStream getProcessInputStream(Long id) {

        // 1. 获取套餐审核的信息
        BusCarPackageAudit audit = busCarPackageAuditMapper.selectBusCarPackageAuditById(id);
        Assert.notNull(audit,"没有找到审核套餐");
        // 2. 获取审核中，高亮点集合
        List<String> highLightedActivities = Collections.emptyList();
        String processDefinitionKey = null;
        if (audit.getStatus() == BusPackageAuditEnum.AUDITING.ordinal()) {
            // 获取高亮信息
            ProcessInstance instance = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(audit.getInstanceId()).singleResult();
            Assert.notNull(instance,"查找不到相应的实例记录");
             processDefinitionKey = instance.getProcessDefinitionKey();
            highLightedActivities = runtimeService
                    .getActiveActivityIds(audit.getInstanceId());
        } else {
            //  不是审核，从历史获取流程定义key
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(audit.getInstanceId()).singleResult();
            Assert.notNull(historicProcessInstance,"查找不到相应的流程记录");
            processDefinitionKey = historicProcessInstance.getProcessDefinitionKey();

        }
        // 3 生成资源流
        List<ProcessDefinition> processDefinitions = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(processDefinitionKey)
                .orderByProcessDefinitionVersion()
                .desc()
                .list();
        Assert.notEmpty(processDefinitions,"非法操作");
        // 获取流程定义文件，生成图片流
        ProcessDefinition processDefinition = processDefinitions.get(0);
        // TODO 方式二 latesVersion
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        DefaultProcessDiagramGenerator generator = new DefaultProcessDiagramGenerator();
        // generateDiagram(bpmn模型，需要高亮节点ID集合，需要高亮连线Id集合)
        return generator.generateDiagram(
                bpmnModel,
                highLightedActivities,
                Collections.emptyList(),
                "宋体",
                "宋体",
                "宋体"
        );
    }

    /**
     * 查询历史审核，我的已办
     * @param busCarPackageAuditVo
     * @return
     */
    @Override
    public List<BusCarPackageAudit> doneQuery(BusCarPackageAuditVo busCarPackageAuditVo) {
        // 1 获取服务类型流程定义相关信息，获取流程定义key
        BusBpmnInfo BpmnType = busBpmnInfoMapper
                .getByBpmnType(BusCarPackageAuditEnum.FLOW_AUDIT_TYPE.ordinal());
        Assert.notNull(BpmnType,"请上传流程定义文件");
        // 2. 查询历史任务表，（通过用户id和流程定义key）:hi-taskinst,最终目标是获取流程实例ids
        String usrId = SecurityUtils.getUserId().toString();
        List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery()
                .processDefinitionKey(BpmnType.getProcessDefinitionKey())
                .taskAssignee(usrId)
                .list();
        Set<String> processIds = historicTaskInstances.stream().map(historicTaskInstance ->
                historicTaskInstance.getProcessInstanceId()
        ).collect(Collectors.toSet());
        Assert.notEmpty(processIds,"没有流程实例id");
        // 3. 通过流程实例ids,查询历史流程实例表，hi-procinst,最终目标是获取businessKeys（服务项id）
        List<HistoricProcessInstance> historicProcessInstances = historyService.createHistoricProcessInstanceQuery()
                .processDefinitionKey(BpmnType.getProcessDefinitionKey())
                .processInstanceIds(processIds).list();
        List<String> businessKeys = historicProcessInstances.stream().map(historicProcessInstance ->
                historicProcessInstance.getBusinessKey()).collect(Collectors.toList());
        Assert.notEmpty(businessKeys,"没有找到业务id");
        // 4. 通过businessKeys获取历史审核套餐信息，（非审核中）
        List<BusCarPackageAudit> busCarPackageAudits = busCarPackageAuditMapper
                .selectBusCarPackageDoneListByBusinessKeys(businessKeys);
        return busCarPackageAudits;
    }

    @Override
    public void cancelCarPackageAudit(Long id) {
        Assert.notNull(id,"非法参数");
        // 1. 获取套餐审核的信息
        BusCarPackageAudit audit = busCarPackageAuditMapper.selectBusCarPackageAuditById(id);
        Assert.notNull(audit,"没有找到审核套餐");
        // 只有审核中的套餐才能撤销
        Assert.state(audit.getStatus() == BusPackageAuditEnum.AUDITING.ordinal(),
                "只有审核中的套餐才能撤销");
        // 2.关闭流程实例
         runtimeService.deleteProcessInstance(audit.getInstanceId(),"手动撤销审核");
        // 3. 修改审核套餐的状态
        BusCarPackageAudit busCarPackageAudit = new BusCarPackageAudit();
        busCarPackageAudit.setId(id);
        busCarPackageAudit.setStatus(BusPackageAuditEnum.CANCEL.ordinal());
        busCarPackageAuditMapper.updateBusCarPackageAudit(busCarPackageAudit);
        // 删除服务项
        busServiceitemMapper.deleteBusServiceitemById(audit.getServiceItemId());
    }


}
